using System;
using System.Collections.Generic;
using System.Windows.Forms;

using OhioState.AssetManaged;
using OhioState.Math;


namespace OhioState.Controls
{
    //
    // Vector Control - encapsulates numeric up downs and combo boxes into a single control
    //  that represents a vector editor.  This is flexible and can easily be set to modify
    //  vectors of size 2, 3 or 4 and value types of float, int and boolean.  Decimal places
    //  and increment steps can be modified to the users liking when in float mode, and the min and
    //  max values can be set when in either float or int mode. This control will autosize to ensure
    //  every value is visible while taking up the least possible space.
    //
    public partial class VectorControl : UserControl
    {
        public enum VectorType
        {
            Float,
            Int,
            Bool
        }
        //
        // Properties of numericUpDowns - matrix size, decimal places, increment and max value
        //  List of the numeric up downs for each matrix size
        //
        private int vectorSize;
        private VectorType vectorType;
        private int decimalPlaces;
        private float increment;
        private float max;
        private List<System.Windows.Forms.NumericUpDown> numericUpDowns;

        //
        // Event for Vector Control which informs subscribers that the control has changed
        //
        public event System.EventHandler ValueChanged;
        //
        // Event helper for firing events
        //
        protected EventsStrategyAbstract _eventsHelper;

        //
        // Constructor - set up all the possible numericUpDowns that we may be using
        //
        public VectorControl()
        {
            InitializeComponent();

            vectorSize = 2;
            vectorType = VectorType.Float;
            decimalPlaces = 5;
            increment = 0.01f;
            max = 1000000f;

            comboBox1.SelectedIndex = 0;
            comboBox2.SelectedIndex = 0;
            comboBox3.SelectedIndex = 0;
            comboBox4.SelectedIndex = 0;

            this.numericUpDown1.ValueChanged += new System.EventHandler(this.control_ValueChanged);
            this.numericUpDown2.ValueChanged += new System.EventHandler(this.control_ValueChanged);
            this.numericUpDown3.ValueChanged += new System.EventHandler(this.control_ValueChanged);
            this.numericUpDown4.ValueChanged += new System.EventHandler(this.control_ValueChanged);
            this.comboBox1.SelectedIndexChanged += new System.EventHandler(this.control_ValueChanged);
            this.comboBox2.SelectedIndexChanged += new System.EventHandler(this.control_ValueChanged);
            this.comboBox3.SelectedIndexChanged += new System.EventHandler(this.control_ValueChanged);
            this.comboBox4.SelectedIndexChanged += new System.EventHandler(this.control_ValueChanged);

            numericUpDowns = new List<System.Windows.Forms.NumericUpDown>();

            //
            // Add all updowns to list
            //
            numericUpDowns.Add(this.numericUpDown1);
            numericUpDowns.Add(this.numericUpDown2);
            numericUpDowns.Add(this.numericUpDown3);
            numericUpDowns.Add(this.numericUpDown4);

            _eventsHelper = new EventsStrategyAsync();
        }

        //
        // Public properties - set basic numericUpDown properties
        //
        public int DecimalPlaces
        {
            get { return decimalPlaces; }
            set
            {
                if (vectorType == VectorType.Float)
                {
                    decimalPlaces = value;

                    SetVisible();
                }
            }
        }

        public float Increment
        {
            get { return increment; }
            set
            {
                if (vectorType == VectorType.Float)
                {
                    increment = value;

                    SetVisible();
                }
            }
        }

        public float Max
        {
            get { return max; }
            set
            {
                max = value;

                this.tableLayoutPanel1.SuspendLayout();
                this.SuspendLayout();

                foreach (System.Windows.Forms.NumericUpDown n in numericUpDowns)
                {
                    n.Maximum = new Decimal(max);
                    n.Minimum = new Decimal(-max);
                }

                this.tableLayoutPanel1.ResumeLayout(false);
                this.tableLayoutPanel1.PerformLayout();
                this.ResumeLayout(false);
                this.PerformLayout();
            }
        }

        //
        // Set the size of the vector, set the visibility of the appropriate number of cells
        //
        public int VectorSize
        {
            get { return vectorSize; }
            set
            {
                if ((value >= 2) && (value <= 4))
                {
                    vectorSize = value;
                    SetVisible();
                }
            }
        }

        public VectorType Type
        {
            get { return vectorType; }
            set
            {
                vectorType = value;
                SetVisible();
            }
        }

        #region Helper Functions

        //
        // Sets the proper visibility of cells
        //
        private void SetVisible ()
        {
            this.tableLayoutPanel1.SuspendLayout();
            this.SuspendLayout();

            if (vectorSize < 3)
            {
                this.numericUpDown3.Visible = false;
                this.comboBox3.Visible = false;
                this.labelZ.Visible = false;
            }
            else
            {
                this.numericUpDown3.Visible = true;
                this.comboBox3.Visible = true;
                this.labelZ.Visible = true;
            }
            if (vectorSize < 4)
            {
                this.numericUpDown4.Visible = false;
                this.comboBox4.Visible = false;
                this.labelW.Visible = false;
            }
            else
            {
                this.numericUpDown4.Visible = true;
                this.comboBox4.Visible = true;
                this.labelW.Visible = true;
            }

            if ((vectorType == VectorType.Float) || (vectorType == VectorType.Int))
            {
                this.numericUpDown1.Visible = true;
                this.numericUpDown2.Visible = true;
                this.comboBox1.Visible = false;
                this.comboBox2.Visible = false;
                this.comboBox3.Visible = false;
                this.comboBox4.Visible = false;

                if (vectorType == VectorType.Float)
                {
                    foreach (System.Windows.Forms.NumericUpDown n in numericUpDowns)
                    {
                        n.DecimalPlaces = decimalPlaces;
                    }
                    foreach (System.Windows.Forms.NumericUpDown n in numericUpDowns)
                    {
                        n.Increment = new Decimal(increment);
                    }
                }
                else // VectorType.Int
                {
                    foreach (System.Windows.Forms.NumericUpDown n in numericUpDowns)
                    {
                        n.DecimalPlaces = 0;
                    }
                    foreach (System.Windows.Forms.NumericUpDown n in numericUpDowns)
                    {
                        n.Increment = new Decimal(1);
                    }
                }
            }
            else // VectorType.Bool
            {
                this.numericUpDown1.Visible = false;
                this.numericUpDown2.Visible = false;
                this.numericUpDown3.Visible = false;
                this.numericUpDown4.Visible = false;
                this.comboBox1.Visible = true;
                this.comboBox2.Visible = true;
            }
            
            this.tableLayoutPanel1.ResumeLayout(false);
            this.tableLayoutPanel1.PerformLayout();
            this.ResumeLayout(false);
            this.PerformLayout();
        }

        #endregion

        #region Vector Accessors
        //
        // Accessor to get and set data in the vector
        //  The accessor will return the type of vector that it is currently set upt to modify.
        //  So depending on the settings of VectorSize and Type, this can return 1 of 9 different 
        //  vector types.  The set will automatically reset the values of these properties if the
        //  set routine is given a type of vector different than what the control is currently modifying.
        //
        public IVector Value
        {
            get
            {
                IVector v = null;
                if (vectorSize == 2)
                {
                    if (vectorType == VectorType.Float)
                    {
                        Vector2 vec = new Vector2();
                        vec[0] = Decimal.ToSingle(numericUpDown1.Value);
                        vec[1] = Decimal.ToSingle(numericUpDown2.Value);
                        v = vec;
                    }
                    else if (vectorType == VectorType.Int)
                    {
                        Vector2i vec = new Vector2i();
                        vec[0] = Decimal.ToInt32(numericUpDown1.Value);
                        vec[1] = Decimal.ToInt32(numericUpDown2.Value);
                        v = vec;
                    }
                    else if (vectorType == VectorType.Bool)
                    {
                        Vector2b vec = new Vector2b();
                        vec[0] = System.Convert.ToBoolean(comboBox1.SelectedIndex);
                        vec[1] = System.Convert.ToBoolean(comboBox2.SelectedIndex);
                        v = vec;
                    }
                }
                else if (vectorSize == 3)
                {
                    if (vectorType == VectorType.Float)
                    {
                        Vector3 vec = new Vector3();
                        vec[0] = Decimal.ToSingle(numericUpDown1.Value);
                        vec[1] = Decimal.ToSingle(numericUpDown2.Value);
                        vec[2] = Decimal.ToSingle(numericUpDown3.Value);
                        v = vec;
                    }
                    else if (vectorType == VectorType.Int)
                    {
                        Vector3i vec = new Vector3i();
                        vec[0] = Decimal.ToInt32(numericUpDown1.Value);
                        vec[1] = Decimal.ToInt32(numericUpDown2.Value);
                        vec[2] = Decimal.ToInt32(numericUpDown3.Value);
                        v = vec;
                    }
                    else if (vectorType == VectorType.Bool)
                    {
                        Vector3b vec = new Vector3b();
                        vec[0] = System.Convert.ToBoolean(comboBox1.SelectedIndex);
                        vec[1] = System.Convert.ToBoolean(comboBox2.SelectedIndex);
                        vec[2] = System.Convert.ToBoolean(comboBox3.SelectedIndex);
                        v = vec;
                    }
                }
                else if (vectorSize == 4)
                {
                    if (vectorType == VectorType.Float)
                    {
                        Vector4 vec = new Vector4();
                        vec[0] = Decimal.ToSingle(numericUpDown1.Value);
                        vec[1] = Decimal.ToSingle(numericUpDown2.Value);
                        vec[2] = Decimal.ToSingle(numericUpDown3.Value);
                        vec[3] = Decimal.ToSingle(numericUpDown4.Value);
                        v = vec;
                    }
                    else if (vectorType == VectorType.Int)
                    {
                        Vector4i vec = new Vector4i();
                        vec[0] = Decimal.ToInt32(numericUpDown1.Value);
                        vec[1] = Decimal.ToInt32(numericUpDown2.Value);
                        vec[2] = Decimal.ToInt32(numericUpDown3.Value);
                        vec[3] = Decimal.ToInt32(numericUpDown4.Value);
                        v = vec;
                    }
                    else if (vectorType == VectorType.Bool)
                    {
                        Vector4b vec = new Vector4b();
                        vec[0] = System.Convert.ToBoolean(comboBox1.SelectedIndex);
                        vec[1] = System.Convert.ToBoolean(comboBox2.SelectedIndex);
                        vec[2] = System.Convert.ToBoolean(comboBox3.SelectedIndex);
                        vec[3] = System.Convert.ToBoolean(comboBox4.SelectedIndex);
                        v = vec;
                    }
                }

                return v;
            }
            set
            {
                if (value is Vector2)
                {
                    VectorSize = 2;
                    Type = VectorType.Float;
                    Vector2 vec = (Vector2)value;
                    numericUpDown1.Value = new Decimal(vec[0]);
                    numericUpDown2.Value = new Decimal(vec[1]);
                }
                else if (value is Vector2i)
                {
                    VectorSize = 2;
                    Type = VectorType.Int;
                    Vector2i vec = (Vector2i)value;
                    numericUpDown1.Value = new Decimal(vec[0]);
                    numericUpDown2.Value = new Decimal(vec[1]);
                }
                else if (value is Vector2b)
                {
                    VectorSize = 2;
                    Type = VectorType.Bool;
                    Vector2b vec = (Vector2b)value;
                    int[] v = vec.getIntValue();
                    comboBox1.SelectedIndex = v[0];
                    comboBox2.SelectedIndex = v[1];
                }
                else if (value is Vector3)
                {
                    VectorSize = 3;
                    Type = VectorType.Float;
                    Vector3 vec = (Vector3)value;
                    numericUpDown1.Value = new Decimal(vec[0]);
                    numericUpDown2.Value = new Decimal(vec[1]);
                    numericUpDown3.Value = new Decimal(vec[2]);
                }
                else if (value is Vector3i)
                {
                    VectorSize = 3;
                    Type = VectorType.Int;
                    Vector3i vec = (Vector3i)value;
                    numericUpDown1.Value = new Decimal(vec[0]);
                    numericUpDown2.Value = new Decimal(vec[1]);
                    numericUpDown3.Value = new Decimal(vec[2]);
                }
                else if (value is Vector3b)
                {
                    VectorSize = 3;
                    Type = VectorType.Bool;
                    Vector3b vec = (Vector3b)value;
                    int[] v = vec.getIntValue();
                    comboBox1.SelectedIndex = v[0];
                    comboBox2.SelectedIndex = v[1];
                    comboBox3.SelectedIndex = v[2];
                }
                else if (value is Vector4)
                {
                    VectorSize = 4;
                    Type = VectorType.Float;
                    Vector4 vec = (Vector4)value;
                    numericUpDown1.Value = new Decimal(vec[0]);
                    numericUpDown2.Value = new Decimal(vec[1]);
                    numericUpDown3.Value = new Decimal(vec[2]);
                    numericUpDown4.Value = new Decimal(vec[3]);
                }
                else if (value is Vector4i)
                {
                    VectorSize = 4;
                    Type = VectorType.Int;
                    Vector4i vec = (Vector4i)value;
                    numericUpDown1.Value = new Decimal(vec[0]);
                    numericUpDown2.Value = new Decimal(vec[1]);
                    numericUpDown3.Value = new Decimal(vec[2]);
                    numericUpDown4.Value = new Decimal(vec[3]);
                }
                else if (value is Vector4b)
                {
                    VectorSize = 4;
                    Type = VectorType.Bool;
                    Vector4b vec = (Vector4b)value;
                    int[] v = vec.getIntValue();
                    comboBox1.SelectedIndex = v[0];
                    comboBox2.SelectedIndex = v[1];
                    comboBox3.SelectedIndex = v[2];
                    comboBox4.SelectedIndex = v[3];
                }
            }
        }

        #endregion

        private void control_ValueChanged(object sender, EventArgs e)
        {
            _eventsHelper.Fire(ValueChanged, this, e);
        }

    }
}
